﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.IO;
using System.Web;

namespace SBS.Common
{

    public class XmlTransform
    {
        public string InputXmlFile { get; set; }
        public string InputXmlString { get; set; }
        /// <summary>
        /// InputXmlNode 可以是 XmlDocument, XmlNode, XPathDocument
        /// </summary>
        public IXPathNavigable InputXmlNode { get; set; }

        public string InputXsltXmlFile { get; set; }
        public XslCompiledTransform InputXslt { get; set; }
        public Hashtable Argus { get; set; }        

        public string TransformToString()
        {            
            MemoryStream ms = TransformToStream();            
            StreamReader reader = new StreamReader(ms);
            string html = reader.ReadToEnd();
            reader.Close();
            ms.Close();
            return html;
        }
        public MemoryStream TransformToStream()
        {            
            MemoryStream ms = new MemoryStream();
            TransformToStream(ms);
            ms.Position = 0;
            return ms;
            //XslCompiledTransform Xct = GetInputXsltFromCache(this.InputXslt, this.InputXsltXmlFile);
            //XsltArgumentList Arguments = InitArgusList(this.Argus);
            //MemoryStream ms = new MemoryStream();
            //IXPathNavigable Xml = GetInputXml(this.InputXmlNode, this.InputXmlString, this.InputXmlFile);
            //if (Xml == null) return null;
            //Xct.Transform(Xml, Arguments, ms);            
            //ms.Position = 0;            
            //return ms;
        }

        public void TransformToStream(Stream Stream)
        {
            XslCompiledTransform Xct = GetInputXsltFromCache(this.InputXslt, this.InputXsltXmlFile);
            XsltArgumentList Arguments = InitArgusList(this.Argus);
            //MemoryStream ms = new MemoryStream();
            IXPathNavigable Xml = GetInputXml(this.InputXmlNode, this.InputXmlString, this.InputXmlFile);
            if (Xml == null) return;
            Xct.Transform(Xml, Arguments, Stream);            
        }

        private static XsltArgumentList InitArgusList(Hashtable Argus)
        {
            if (Argus == null) return null;
            XsltArgumentList Arguments = new XsltArgumentList();
            foreach (string key in Argus.Keys)
            {
                if (key.StartsWith("urn:"))
                {
                    Arguments.AddExtensionObject(key, Argus[key]);
                }
                else
                {
                    Arguments.AddParam(key, String.Empty, Argus[key]);
                }
            }
            return Arguments;
        }
        private static XslCompiledTransform GetInputXsltFromCache(XslCompiledTransform InputXslt, string InputXsltXmlFile)
        {
            if (InputXslt != null) return InputXslt;
            return GetXslProcessInMemory(InputXsltXmlFile);
        }
        private static IXPathNavigable GetInputXml(IXPathNavigable InputXmlNode, string InputXmlString, string InputXmlFile)
        {            
            if (InputXmlNode != null)
            {
                return InputXmlNode;
            }
            if (!string.IsNullOrEmpty(InputXmlString))
            {                
                TextReader tr = new StringReader(InputXmlString);
                XPathDocument xdom = new XPathDocument(tr);
                tr.Close();
                return xdom;                
            }
            if (!string.IsNullOrEmpty(InputXmlFile) && File.Exists(InputXmlFile))
            {
                XPathDocument xdom = new XPathDocument(InputXmlFile);
                return xdom;
            }
            return null;
        }
        /// <summary>
        /// 从 HttpRuntime.Cache 中获取已编译的 Xslt 样式缓存。
        /// </summary>
        /// <param name="XsltFile">Xslt 文件的完整路径，也作为 HttpRuntime.Cache 集合中的键。</param>
        /// <returns></returns>
        public static XslCompiledTransform GetXslProcessInMemory(string XsltFile)
        {
            if (HttpRuntime.Cache[XsltFile] != null)
            {
                return (XslCompiledTransform)HttpRuntime.Cache[XsltFile];
            }
            XmlReaderSettings Setting = new XmlReaderSettings();
            Setting.ProhibitDtd = false;
            Setting.XmlResolver = new XmlUrlResolver();
            Setting.IgnoreComments = true;
            Setting.IgnoreWhitespace = true;

            XslCompiledTransform Xct = new XslCompiledTransform();
            XsltSettings xs = new XsltSettings(true, true);
            XmlUrlResolver resolver = new XmlUrlResolver();
            resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
            
            using (XmlReader Xr = XmlReader.Create(XsltFile, Setting))
            {
                Xct.Load(Xr, xs, resolver);
                System.Web.Caching.CacheDependency Dep = new System.Web.Caching.CacheDependency(XsltFile);
                HttpRuntime.Cache.Insert(XsltFile, Xct, Dep);
                return Xct;
            }
            
        }
        //public static XmlElement CreateSystemElement(XmlDocument Dom)
        //{
        //    XmlElement System = Dom.CreateElement("system");
            
        //    XmlWriterSettings Setting = new XmlWriterSettings();
        //    Setting.Encoding = Encoding.UTF8;
        //    Setting.OmitXmlDeclaration = true;

        //    StringBuilder sb = new StringBuilder();
        //    XmlWriter Writer = XmlWriter.Create(sb, Setting);            
            
        //    Writer.WriteStartElement("url");            
        //    foreach (string key in HttpContext.Current.Request.QueryString)
        //    {
        //        if (!string.IsNullOrEmpty(key) && "0123456789".IndexOf(key[0]) < 0 )//xml的属性名不能用数字开头
        //        {
        //            Writer.WriteAttributeString(key, HttpContext.Current.Request.QueryString[key]);                    
        //        }
        //    }
        //    Writer.WriteEndElement();
        //    Writer.Close();

        //    StringBuilder sb2 = new StringBuilder();
        //    XmlWriter Writer2 = XmlWriter.Create(sb2, Setting);
        //    Writer2.WriteStartElement("http");
        //    Writer2.WriteStartElement("cookies");
        //    foreach (string key in HttpContext.Current.Request.Cookies.AllKeys)
        //    {
        //        if (!string.IsNullOrEmpty(key) && "0123456789".IndexOf(key[0]) <0 )
        //        {
        //            string val = HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.Cookies[key].Value);
        //            Writer2.WriteAttributeString(key, val);                    
        //        }
        //    }
        //    Writer2.WriteEndElement();
        //    Writer2.WriteStartElement("variable");
        //    if (HttpContext.Current.Request.UserLanguages != null)
        //    {
        //        Writer2.WriteAttributeString("lang", string.Join(",", HttpContext.Current.Request.UserLanguages));
        //    }
        //    Writer2.WriteAttributeString("servertime", SBS.Common.Utility.GetNowTime());
        //    Writer2.WriteEndElement();
        //    Writer2.WriteEndElement();
        //    Writer2.Close();
        //    sb.Append(sb2.ToString());
        //    System.InnerXml = sb.ToString();
        //    return System;            
        //}
        public static string Transform(XPathNavigator InputXml, string InputXsltFile, Hashtable Argus)
        {
            XmlTransform Xt = new XmlTransform();
            Xt.InputXmlNode = InputXml;
            Xt.InputXsltXmlFile = InputXsltFile;
            Xt.Argus = Argus;            
            return Xt.TransformToString();
        }
        public static string Transform(XPathNavigator InputXml, string InputXsltFile)
        {
            return Transform(InputXml, InputXsltFile, null);
        }
        public static string Transform(string InputXml, string InputXsltFile, Hashtable Argus)
        {
            XPathDocument xdom;
            string XmlString = InputXml.Trim();
            if (XmlString.StartsWith("<") && XmlString.EndsWith(">"))
            {
                TextReader tr = new StringReader(XmlString);
                xdom = new XPathDocument(tr);
                tr.Close();
            }
            else
            {
                xdom = new XPathDocument(InputXml);
            }            
            return Transform(xdom.CreateNavigator(), InputXsltFile, Argus);
        }
        public static string Transform(string InputXml, string InputXsltFile)
        {
            return Transform(InputXml, InputXsltFile, null);
        }
    }
}
